/**
* AutoSWF - Cody Cushing. March 26, 2009
* Copyright (c) 2009 Cody Cushing
* No use restrictions. Maintain this notice in all versions. 
**/

package com.autoswf.lattice
{
	import com.autoswf.core.Link;
	
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	
	
	/**
	 * Basic unit for executing a graph of synchronous and/or concurrent commands. 
	 */	
	public class Lattice implements ILattice
	{
		protected var _nextNodes:Array;
		protected var _previousNodes:Array;
		
		
		/**
		 * Constructor. 
		 */		
		public function Lattice()
		{
			_nextNodes = [];
			_previousNodes = [];
		}
		
		
		protected var _hasCompleted:Boolean;
		public function get hasCompleted():Boolean
		{
			return _hasCompleted;
		}
		
		
		protected var _executeObj:Object;
		protected var _executeParams:Array;
		/**
		 * A closure or command to execute when this lattice can be run. 
		 * 
		 * @param object  A closure or command with public "execute" method.
		 * @param rest  Parameters to be passed to the closure on execute. 
		 */
		public function onExecute(object:Object, ...rest:Array):Lattice
		{
			_executeObj = object;
			_executeParams = rest;
			return this;
		}
		
		
		/** Executes a closure or command when all parent lattice nodes have completed. */
		public function execute():void
		{
			/* Check that each upstream lattice task has completed. */
			for each(var lattice:ILattice in _previousNodes)
			{
				if(!lattice.hasCompleted) /* exit if any tasks haven't completed. */
				{
					return;
				}
			}
			
			preExecute();
			
			if(_executeObj)
			{
				/* Get the closure or "execute" method from a command for starting the task. */
				var func:Function = _executeObj.hasOwnProperty("execute") ? _executeObj["execute"] : _executeObj as Function;
				func && func.apply(null, _executeParams);
			}
			
			postExecute();
		}
		
		
		/** Invoked just before the command is executed. Subclass may add listeners at this point. */		
		protected function preExecute():void
		{
			
		}
		
		
		/** Invoked after the command is executed. Override to prevent immediate execution of next lattice node(s). */		
		protected function postExecute():void
		{
			executeNext();
		}
		
		
		/** Begin execution of any child Lattice nodes. */
		public function executeNext():void
		{
			_hasCompleted = true;
			
			for each(var lattice:ILattice in _nextNodes)
			{
				lattice.execute();
			}
		}

		public function addNext(lattice:ILattice):void
		{
			_nextNodes.push(lattice);
		}
		
		
		public function addPrevious(lattice:ILattice):void
		{
			_previousNodes.push(lattice);
		}
		
		public function join(nextLattice:Lattice):Lattice
		{
			nextLattice.addPrevious(this);
			addNext(nextLattice);
			return nextLattice;
		}
		
		public function createAndJoin():Lattice
		{
			return join(new Lattice());
		}
	}
}